package cn.Replay;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HexReplayViewer extends JFrame {

    private int gridSize = 11; // 动态棋盘大小（默认11）
    private HexBoardPanel boardPanel;
    private final List<MoveRecord> moveRecords;
    private int currentMoveIndex;
    private JLabel infoLabel;
    private Timer autoPlayTimer;
    private int autoPlayDelay = 1000; // 默认1秒

    private final Map<String, String> headerInfo = new LinkedHashMap<>();

    public HexReplayViewer() {
        setTitle("六贯棋棋谱");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        moveRecords = new ArrayList<>();
        currentMoveIndex = -1;

        // 初始 gridSize
        boardPanel = new HexBoardPanel(gridSize);
        add(boardPanel, BorderLayout.CENTER);

        setupControls();

        pack(); 
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void setupControls() {
        JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
        controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        JButton loadButton = new JButton("加载棋谱");
        JButton prevButton = new JButton("上一步");
        JButton nextButton = new JButton("下一步");
        JButton autoPlayButton = new JButton("自动播放");
        JButton speedUpButton = new JButton("加速");
        JButton speedDownButton = new JButton("减速");

        infoLabel = new JLabel("请加载棋谱文件");
        infoLabel.setPreferredSize(new Dimension(300, 30));

        loadButton.addActionListener(e -> loadGameRecord());
        prevButton.addActionListener(e -> showPreviousMove());
        nextButton.addActionListener(e -> showNextMove());
        autoPlayButton.addActionListener(e -> toggleAutoPlay());
        speedUpButton.addActionListener(e -> speedUp());
        speedDownButton.addActionListener(e -> speedDown());

        controlPanel.add(loadButton);
        controlPanel.add(prevButton);
        controlPanel.add(nextButton);
        controlPanel.add(autoPlayButton);
        controlPanel.add(speedUpButton);
        controlPanel.add(speedDownButton);
        controlPanel.add(infoLabel);

        add(controlPanel, BorderLayout.SOUTH);
    }

    private void loadGameRecord() {
        JFileChooser fileChooser = new JFileChooser();
    
        File recordsDirectory = new File(System.getProperty("user.home") + File.separator + "Documents" + File.separator + "hexgame");
        if (!recordsDirectory.exists()) recordsDirectory.mkdirs();
        fileChooser.setCurrentDirectory(recordsDirectory);

        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            try {
                parseGameRecord(fileChooser.getSelectedFile().getAbsolutePath());
                currentMoveIndex = -1;
                boardPanel.reset();
                updateInfoLabel();
            } catch (IOException e) {
                JOptionPane.showMessageDialog(this, "读取棋谱文件失败: " + e.getMessage(),
                        "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    /**
     * 解析棋谱文件。支持头部 [BoardSize "N"] 或 [棋盘 大小 "N"] 来动态设置棋盘大小。
     * Moves 格式与 Record.writeToFile 输出保持一致： R(A,1) 或 B(AB,11) 可选后缀 [123ms]
     */
    private void parseGameRecord(String filePath) throws IOException {
        moveRecords.clear();
        headerInfo.clear();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            boolean inMoves = false;
            Pattern headerPattern = Pattern.compile("^\\[(.+?)\\s+\"(.+?)\"\\]");
            Pattern movePattern = Pattern.compile("([RB])\\(([A-Z]{1,3}),(\\d{1,4})\\)(?: \\[(\\d+)ms\\])?");
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty()) continue;

                
                Matcher h = headerPattern.matcher(line);
                if (h.find()) {
                    String key = h.group(1).trim();
                    String value = h.group(2).trim();
                    headerInfo.put(key, value);
                    
                    if (key.equalsIgnoreCase("BoardSize") || key.contains("棋盘")) {
                        try {
                            int newSize = Integer.parseInt(value);
                            if (newSize > 0 && newSize != gridSize) {
                                gridSize = newSize;
                                //
                                getContentPane().remove(boardPanel);
                                boardPanel = new HexBoardPanel(gridSize);
                                add(boardPanel, BorderLayout.CENTER);
                                revalidate();
                                repaint();
                                pack();
                            }
                        } catch (Exception ignored) {
                        }
                    }
                    
                    if (key.equalsIgnoreCase("Moves")) inMoves = true;
                    continue;
                }

                // 关键文本标识进入 Moves 区块
                if (line.equalsIgnoreCase("Moves:")) {
                    inMoves = true;
                    continue;
                }

                if (inMoves) {
                    Matcher m = movePattern.matcher(line);
                    while (m.find()) {
                        String color = m.group(1);
                        int col = m.group(2).charAt(0) - 'A';
                        int row = gridSize - Integer.parseInt(m.group(3));
                        long stepMs = 0L;
                        if (m.group(4) != null) {
                            try { stepMs = Long.parseLong(m.group(4)); } catch (Exception ignored) {}
                        }
                        int team = color.equals("R") ? 1 : 2;
                        // 验证坐标合法性：如果行/列超出当前 gridSize，仍然加入但播放会忽略越界步
                        moveRecords.add(new MoveRecord(team, col, row, stepMs));
                    }
                }
            }
        }
    }

    private int parseColumnCoordinate(String colStr) {
        colStr = colStr.toUpperCase();
        int result = 0;
        for (int i = 0; i < colStr.length(); i++) {
            char c = colStr.charAt(i);
            result = result * 26 + (c - 'A' + 1);
        }
        return result - 1;
    }

    private String colIndexToLabel(int col) {
        if (col < 0) return "?";
        StringBuilder sb = new StringBuilder();
        int n = col;
        while (n >= 0) {
            int rem = n % 26;
            sb.insert(0, (char) ('A' + rem));
            n = n / 26 - 1;
        }
        return sb.toString();
    }

    private void showNextMove() {
        if (moveRecords.isEmpty()) {
            JOptionPane.showMessageDialog(this, "请先加载棋谱文件", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
        }
        if (currentMoveIndex < moveRecords.size() - 1) {
            currentMoveIndex++;
            MoveRecord move = moveRecords.get(currentMoveIndex);
            // 忽略越界步
            if (move.row >= 0 && move.row < gridSize && move.col >= 0 && move.col < gridSize) {
                boardPanel.setPiece(move.row, move.col, move.team, currentMoveIndex + 1);
            }
            updateInfoLabel();
        }
    }

    private void showPreviousMove() {
        if (moveRecords.isEmpty() || currentMoveIndex < 0) return;
        MoveRecord move = moveRecords.get(currentMoveIndex);
        if (move.row >= 0 && move.row < gridSize && move.col >= 0 && move.col < gridSize) {
            boardPanel.removePiece(move.row, move.col);
        }
        currentMoveIndex--;
        updateInfoLabel();
    }

    private void toggleAutoPlay() {
        if (moveRecords.isEmpty()) return;

        if (autoPlayTimer != null && autoPlayTimer.isRunning()) {
            autoPlayTimer.stop();
            return;
        }

        //
        boardPanel.reset();
        currentMoveIndex = -1;

        autoPlayTimer = new Timer(autoPlayDelay, e -> {
            if (currentMoveIndex < moveRecords.size() - 1) {
                showNextMove();
            } else {
                autoPlayTimer.stop();
            }
        });
        autoPlayTimer.start();
    }

    private void speedUp() {
        if (autoPlayDelay > 200) {
            autoPlayDelay -= 200;
            if (autoPlayTimer != null && autoPlayTimer.isRunning()) autoPlayTimer.setDelay(autoPlayDelay);
        }
    }

    private void speedDown() {
        autoPlayDelay += 200;
        if (autoPlayTimer != null && autoPlayTimer.isRunning()) autoPlayTimer.setDelay(autoPlayDelay);
    }

    private void updateInfoLabel() {
        if (moveRecords.isEmpty()) {
            infoLabel.setText("请加载棋谱文件");
        } else {
            int shownIndex = Math.max(0, currentMoveIndex + 1);
            String nextPlayer = ((currentMoveIndex + 1) % 2 == 0) ? "红方" : "蓝方";
            String coord = "";
            if (currentMoveIndex >= 0 && currentMoveIndex < moveRecords.size()) {
                MoveRecord m = moveRecords.get(currentMoveIndex);
                coord = String.format("  坐标: %s%d", colIndexToLabel(m.col), m.row + 1);
            }
            infoLabel.setText(String.format("步数: %d/%d - 下一手: %s%s", shownIndex, moveRecords.size(), nextPlayer, coord));
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            new HexReplayViewer();
        });
    }

    // --- 数据模型 ---
    private static class MoveRecord {
        final int team; // 1: 红方, 2: 蓝方
        final int row;
        final int col;
        final long stepTime;

        MoveRecord(int team, int row, int col, long stepTime) {
            this.team = team;
            this.row = row;
            this.col = col;
            this.stepTime = stepTime;
        }
    }

    // --- 视图组件 ---

    private static class Hex {
        private final int q, r; 
        private Polygon polygon;
        private int team = 0; //
        private int moveNumber = 0;
        private Point2D center;
        private final int size;

        public Hex(int q, int r, int size) {
            this.q = q;
            this.r = r;
            this.size = size;
        }

        private Polygon createHexagon(Point2D center, int size) {
            Polygon polygon = new Polygon();
            for (int i = 0; i < 6; i++) {
                double angle_deg = 60 * i - 30;
                double angle_rad = Math.PI / 180 * angle_deg;
                int x = (int) (center.getX() + size * Math.cos(angle_rad));
                int y = (int) (center.getY() + size * Math.sin(angle_rad));
                polygon.addPoint(x, y);
            }
            return polygon;
        }

        public void updateCenter(Point2D center) {
            this.center = center;
            this.polygon = createHexagon(center, size);
        }

        public void draw(Graphics2D g2d) {
            if (polygon == null) return;

            //
            g2d.setColor(new Color(220, 200, 170)); 
            g2d.fill(polygon);
            g2d.setColor(Color.BLACK);
            g2d.draw(polygon);

            //
            if (team != 0) {
                // 颜色
                Color pieceColor = (team == 1) ? new Color(220, 50, 50) : new Color(50, 50, 220);
                g2d.setColor(pieceColor);
                g2d.fill(polygon);

                // 高光效果
                GradientPaint highlight = new GradientPaint(
                        (float) (center.getX() - polygon.getBounds().width / 4),
                        (float) (center.getY() - polygon.getBounds().height / 4),
                        new Color(255, 255, 255, 100),
                        (float) center.getX(), (float) center.getY(),
                        new Color(255, 255, 255, 0)
                );
                g2d.setPaint(highlight);
                g2d.fill(polygon);

                // 边框
                g2d.setColor(Color.BLACK);
                g2d.draw(polygon);

                // 步数
                if (moveNumber > 0) {
                    g2d.setColor(Color.WHITE);
                    g2d.setFont(new Font("Arial", Font.BOLD, 14));
                    String text = String.valueOf(moveNumber);
                    FontMetrics fm = g2d.getFontMetrics();
                    int textWidth = fm.stringWidth(text);
                    int textHeight = fm.getAscent();
                    g2d.drawString(text, (int) (center.getX() - textWidth / 2.0), (int) (center.getY() + textHeight / 3.0));
                }
            }
        }

        public boolean contains(Point p) {
            return polygon != null && polygon.contains(p);
        }

        public void setPiece(int team, int moveNumber) {
            this.team = team;
            this.moveNumber = moveNumber;
        }

        public void removePiece() {
            this.team = 0;
            this.moveNumber = 0;
        }
    }


    private class HexBoardPanel extends JPanel {
        private Hex[][] hexGrid;
        private final int hexSize = 25; //半径
        private int panelGridSize;

        public HexBoardPanel(int size) {
            this.panelGridSize = size;
            this.hexGrid = new Hex[size][size];
            setPreferredSize(new Dimension(800, 800));
            initializeGrid(size);
        }

        private void initializeGrid(int size) {
            hexGrid = new Hex[size][size];
            for (int r = 0; r < size; r++) {
                for (int q = 0; q < size; q++) {
                    hexGrid[r][q] = new Hex(q, r, hexSize);
                }
            }
            this.panelGridSize = size;
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            g2d.setColor(new Color(245, 235, 220));
            g2d.fillRect(0, 0, getWidth(), getHeight());

            int size = panelGridSize;

            double boardWidthPx = Math.sqrt(3) * hexSize * (size + 0.5);
            double boardHeightPx = 1.5 * hexSize * (size + 1);

            double offsetX = (getWidth() - boardWidthPx) / 2;
            double offsetY = (getHeight() - boardHeightPx) / 2;

            for (int r = 0; r < size; r++) {
                for (int q = 0; q < size; q++) {
                    double x = offsetX - 100 + hexSize * Math.sqrt(3) * (q + 0.5 * r);
                    double y = offsetY + hexSize * 1.5 * r;
                    hexGrid[r][q].updateCenter(new Point2D.Double(x, y));
                    hexGrid[r][q].draw(g2d);
                }
            }
        }

        public void reset() {
            if (hexGrid == null) return;
            for (Hex[] row : hexGrid) {
                for (Hex hex : row) {
                    hex.removePiece();
                }
            }
            repaint();
        }

        public void setPiece(int row, int col, int team, int moveNumber) {
            if (hexGrid == null) return;
            if (row >= 0 && row < hexGrid.length && col >= 0 && col < hexGrid.length) {
                hexGrid[row][col].setPiece(team, moveNumber);
                repaint();
            }
        }

        public void removePiece(int row, int col) {
            if (hexGrid == null) return;
            if (row >= 0 && row < hexGrid.length && col >= 0 && col < hexGrid.length) {
                hexGrid[row][col].removePiece();
                repaint();
            }
        }
    }
}